<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no">
    <title>Online 3D Viewer</title>
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <script type="text/javascript" src="./visualization/three.min-129.js"></script>
    <script type="text/javascript" src="./visualization/o3dv.min-0.7.24.js"></script>
    <script type='text/javascript'>
        OV.ExternalLibLocation = './visualization/libs';

        let Init3DViewerElement = function (parentDiv, modelUrls, parameters)
        {
            if (!parameters) {
                parameters = {};
            }

            let canvas = document.createElement ('canvas');
            parentDiv.appendChild (canvas);

            let viewer = new OV.Viewer ();
            viewer.Init (canvas);

            let width = parentDiv.clientWidth;
            let height = parentDiv.clientHeight;
            viewer.Resize (width, height);

            let loader = new OV.ThreeModelLoader ();
            let progressDiv = null;
            loader.Init ({
                onLoadStart : () => {
                    canvas.style.display = 'none';
                    progressDiv = document.createElement ('div');
                    parentDiv.appendChild (progressDiv);
                    progressDiv.innerHTML = 'Loading model...';
                    document.getElementsByClassName('loadingText')[0].innerHTML = '下载模型中...'
                },
                onImportStart : () => {
                    progressDiv.innerHTML = 'Importing model...'
                    document.getElementsByClassName('loadingText')[0].innerHTML = '导入模型中...'
                },
                onVisualizationStart : () => {
                    progressDiv.innerHTML = 'Visualizing model...';
                    document.getElementsByClassName('loadingText')[0].innerHTML = '渲染模型中...'
                },
                onModelFinished : (importResult, threeMeshes) => {
                    document.getElementsByClassName('loading')[0].style.display='none';
                    document.getElementsByClassName('online_3d_viewer')[0].style.visibility='visible';
                    parentDiv.removeChild (progressDiv);
                    canvas.style.display = 'inherit';
                    viewer.AddMeshes (threeMeshes);
                    let boundingSphere = viewer.GetBoundingSphere ((meshUserData) => {
                        return true;
                    });
                    viewer.AdjustClippingPlanesToSphere (boundingSphere);
                    if (parameters.camera) {
                        viewer.SetCamera (parameters.camera);
                    } else {
                        viewer.SetUpVector (importResult.upVector, false);
                    }
                    viewer.FitSphereToWindow (boundingSphere, false);
                },
                onTextureLoaded : () => {
                    viewer.Render ();
                },
                onLoadError : (importError) => {
                    let message = 'Unknown error';
                    if (importError.code === OV.ImportErrorCode.NoImportableFile) {
                        message = 'No importable file found';
                    } else if (importError.code === OV.ImportErrorCode.ImportFailed) {
                        message = 'Failed to import model.';
                    }
                    if (importError.message !== null) {
                        message += ' (' + importError.message + ')';
                    }
                    progressDiv.innerHTML = message;
                }
            });

            if (modelUrls === null || modelUrls.length === 0) {
                return null;
            }

            if (parameters.backgroundColor) {
                viewer.SetBackgroundColor (parameters.backgroundColor);
            }

            if (parameters.environmentMap) {
                viewer.SetEnvironmentMap (parameters.environmentMap);
            }

            let settings = new OV.ImportSettings ();
            if (parameters.defaultColor) {
                settings.defaultColor = parameters.defaultColor;
            }

            loader.LoadFromUrlList (modelUrls, settings);
            return {
                element: parentDiv,
                viewer: viewer
            };
        };

        let Init3DViewerElements = function (onReady)
        {
            function LoadElement (element)
            {
                let camera = null;
                let cameraParams = element.getAttribute ('camera');
                if (cameraParams) {
                    camera = OV.ParameterConverter.StringToCamera (cameraParams);
                }

                let backgroundColor = null;
                let backgroundColorParams = element.getAttribute ('backgroundcolor');
                if (backgroundColorParams) {
                    backgroundColor = OV.ParameterConverter.StringToColor (backgroundColorParams);
                }

                let defaultColor = null;
                let defaultColorParams = element.getAttribute ('defaultcolor');
                if (defaultColorParams) {
                    defaultColor = OV.ParameterConverter.StringToColor (defaultColorParams);
                }

                let environmentMap = null;
                let environmentMapParams = element.getAttribute ('environmentmap');
                if (environmentMapParams) {
                    let environmentMapParts = environmentMapParams.split (',');
                    if (environmentMapParts.length === 6) {
                        environmentMap = environmentMapParts;
                    }
                }

                let modelUrls = null;
                let modelParams = element.getAttribute ('model');
                if (modelParams) {
                    modelUrls = OV.ParameterConverter.StringToModelUrls (modelParams);
                }

                return Init3DViewerElement (element, modelUrls, {
                    camera,
                    backgroundColor,
                    defaultColor,
                    environmentMap
                });
            }

            let viewerElements = [];
            window.addEventListener ('load', () => {
                let elements = document.getElementsByClassName ('online_3d_viewer');
                for (let i = 0; i < elements.length; i++) {
                    let element = elements[i];
                    let viewerElement = LoadElement (element);
                    viewerElements.push (viewerElement);
                }
                if (onReady !== undefined && onReady !== null) {
                    onReady (viewerElements);
                }
            });

            window.addEventListener ('resize', () => {
                for (let i = 0; i < viewerElements.length; i++) {
                    let viewerElement = viewerElements[i];
                    let width = viewerElement.element.clientWidth;
                    let height = viewerElement.element.clientHeight;
                    viewerElement.viewer.Resize (width, height);
                }
            });
        };

        // 默认加载加载loading
        Init3DViewerElements((rs) => {
            // 隐藏loading
            let viewer = rs[0].viewer;
            let scene = viewer.scene;
            let camera = viewer.camera;
            let renderer = viewer.renderer;
            let parameters = [];
            function render() {
                scene.traverse((obj) => {
                    if (obj instanceof THREE.Mesh) {
                        obj.rotation.y = obj.rotation.y + 0.01;
                    }
                })
                const time = Date.now() * 0.00005;
                for ( let i = 0; i < scene.children.length; i ++ ) {
                    const object = scene.children[ i ];
                    if ( object instanceof THREE.Points ) {
                        // object.rotation.y = time * ( i < 4 ? i + 1 : - ( i + 1 ) );
                        object.rotation.x = object.rotation.x + 0.0025;
                    }
                }
                for ( let i = 0; i < materials.length; i ++ ) {
                    const color = parameters[ i ][ 0 ];
                    const h = ( 360 * ( color[ 0 ] + time ) % 360 ) / 360;
                    materials[ i ].color.setHSL( h, color[ 1 ], color[ 2 ] );
                }
                requestAnimationFrame(render)
                renderer.render(scene, camera);
            }
            const materials = [];
            function init() {
                const geometry = new THREE.BufferGeometry();
                const vertices = [];
                const textureLoader = new THREE.TextureLoader();
                const sprite1 = textureLoader.load( 'snowflake1.png' );
                const sprite2 = textureLoader.load( 'snowflake2.png' );
                const sprite3 = textureLoader.load( 'snowflake3.png' );
                const sprite4 = textureLoader.load( 'snowflake4.png' );
                const sprite5 = textureLoader.load( 'snowflake5.png' );
                for ( let i = 0; i < 30000; i ++ ) {
                    const x = Math.random() * 12000 - 6000 ;
                    const y = Math.random() * 12000 - 6000;
                    const z = Math.random() * 12000 - 6000;
                    vertices.push( x, y, z );
                }
                geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
                parameters = [
                    [[ 1.0, 0.2, 0.5 ], sprite2, 30 ],
                    [[ 0.95, 0.1, 0.5 ], sprite3, 30 ],
                    [[ 0.90, 0.05, 0.5 ], sprite1, 30 ],
                    [[ 0.85, 0, 0.5 ], sprite5, 30 ],
                    [[ 0.80, 0, 0.5 ], sprite4, 30 ]
                ];

                for ( let i = 0; i < parameters.length; i ++ ) {
                    const color = parameters[ i ][ 0 ];
                    const sprite = parameters[ i ][ 1 ];
                    const size = parameters[ i ][ 2 ];
                    materials[ i ] = new THREE.PointsMaterial( { size: size, map: sprite, blending: THREE.AdditiveBlending, depthTest: false, transparent: true } );
                    materials[ i ].color.setHSL( color[ 0 ], color[ 1 ], color[ 2 ] );
                    const particles = new THREE.Points( geometry, materials[ i ] );
                    particles.rotation.x = Math.random() * 6;
                    particles.rotation.y = Math.random() * 6;
                    particles.rotation.z = Math.random() * 6;
                    scene.add( particles );
                }
            }
            init();
            render();
        });
    </script>
    <style>
        body, html {
            padding: 0;
            margin: 0;
        }
        .online_3d_viewer {
            position: relative;
        }
        .online_3d_viewer .text {
            position: absolute;
            top: 0;
            font-size: 20px;
            color: red;
            left: 0;
            right: 0;
            text-align: center;
        }
        .loading{
            position: absolute;
            top:0;
            bottom: 0;
            left: 50%;
            right: 0;
            z-index: 999;
            line-height: 100vh;
            margin-left: -100px;
        }
        .loading span{
            display: inline-block;
            width: 20px;
            border-radius: 4px;
            background: lightgreen;
            -webkit-animation: load 1s ease infinite;
        }
        @-webkit-keyframes load{
            0%,100%{
                height: 100px;
                background: rebeccapurple;
            }
            50%{
                height: 170px;
                margin: -15px 0;
                background: red;
            }
        }
        .loading span:nth-child(2){
            -webkit-animation-delay:0.2s;
        }
        .loading span:nth-child(3){
            -webkit-animation-delay:0.4s;
        }
        .loading span:nth-child(4){
            -webkit-animation-delay:0.6s;
        }
        .loading span:nth-child(5){
            -webkit-animation-delay:0.8s;
        }
    </style>
</head>

<body>
<div class="loading">
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <a class="loadingText">需要等待两分钟左右...</a>
</div>
<div class="online_3d_viewer"
     style="visibility: hidden;height: 100vh"
     model="fbxfile.fbx"
     defaultcolor="200,0,0"
     backgroundcolor="0,0,0"
     edgesettings="on,0,0,0,1">
    <div class="text">圣诞快乐</div>
</div>
</body>

</html>
